/*-
 * WritePhonebookEntry.java
 *
 * $LastChangedBy:  $
 * $LastChangedRevision:  $
 * $LastChangedDate:  $
 * $HeadURL: $
 *
 * Copyright (c) 2008, Stein Gunnar Bakkeby
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Stein Gunnar Bakkeby nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.googlecode.attention.at;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.googlecode.attention.PhonebookEntry;



public class WritePhonebookEntry extends AtCommand<WritePhonebookEntry> {

  private int firstIndex;
  private int lastIndex;
  private int maxNumberLength;
  private int minTON;
  private int maxTON;
  private int maxTextLength;
  private boolean informationPopulated = false;

  public WritePhonebookEntry(final AtListener<WritePhonebookEntry> listener) {
    super(listener);
  }
  
  @Override
  protected WritePhonebookEntry getThis() {
    return this;
  }
  
  /**
   * Running this command will make populate information regarding the
   * phonebook memory storage and the maximum length of both the number and
   * the text associated with this number. If this object is re-used to write
   * phonebook entries then the populated information will be used to validate
   * the given arguments.
   * 
   * @see #getFirstIndex()
   * @see #getLastIndex()
   * @see #getMaxNumberLength()
   * @see #getMinTypeOfNumber()
   * @see #getMaxTypeOfNumber()
   * @see #getMaxTextLength()
   */
  public void prepareTest() {
    setCommand("AT+CPBW=?", Command.TEST);
  }
  
  protected void parseTest(final String response) {
    /* Group(0) = +CPBW: (1-200),20,(128-255),30
     * Group:             1   2   3    4   5   6
     * Group(1) = 1
     * Group(2) = 200
     * Group(3) = 20
     * Group(4) = 128
     * Group(5) = 255
     * Group(6) = 30
     */
    final Pattern pattern = Pattern.compile(
        "\\+CPBW: [(]([0-9])-([0-9]+)[)],([0-9]+),[(]([0-9]+)-([0-9]+)[)],([0-9]+)");
    final Matcher matcher = pattern.matcher(response);
    if (matcher.find()) {
      firstIndex      = Integer.parseInt(matcher.group(1));
      lastIndex       = Integer.parseInt(matcher.group(2));
      maxNumberLength = Integer.parseInt(matcher.group(3));
      minTON          = Integer.parseInt(matcher.group(4));
      maxTON          = Integer.parseInt(matcher.group(5));
      maxTextLength   = Integer.parseInt(matcher.group(6));
      informationPopulated = true;
    }
  }
  
  /**
   * This will delete the phonebook entry at the given index. For writing
   * phonebook entries see the other prepareWrite methods. If this object
   * has been used before to run a test command to populate information
   * regarding the memory storage, then that information will be used to
   * validate the given arguments.
   * 
   * @param memoryIndex The phonebook entry to delete
   * @throws IllegalArgumentException If argument validation fails
   * @see #prepareWrite(int, String, int, String)
   * @see #prepareWrite(String, int, String)
   */
  public void prepareWrite(final int memoryIndex) {
    if (informationPopulated) {
      if (memoryIndex < firstIndex) {
        throw new IllegalArgumentException("memoryIndex < firstIndex"); 
      } else if (memoryIndex > lastIndex) {
        throw new IllegalArgumentException("memoryIndex > lastIndex");
      }
    }
    setCommand("AT+CPBW=" + memoryIndex, Command.WRITE);
  }
  
  /**
   * This will write the phonebook entry at the given memory index. If this
   * object has been used before to run a test command to populate information
   * regarding the memory storage, then that information will be used to
   * validate the given arguments.
   * 
   * @param memoryIndex The phonebook entry to delete
   * @throws IllegalArgumentException If argument validation fails
   * @see #prepareWrite(String, int, String)
   */
  public void prepareWrite(final int memoryIndex,
                           final String number,
                           final int typeOfNumber,
                           final String text) {
    if (informationPopulated) {
      if (memoryIndex < firstIndex) {
        throw new IllegalArgumentException("memoryIndex < firstIndex"); 
      } else if (memoryIndex > lastIndex) {
        throw new IllegalArgumentException("memoryIndex > lastIndex");
      } else if (number == null) {
        throw new IllegalArgumentException("number is null");
      } else if (number.length() > maxNumberLength) {
        throw new IllegalArgumentException("number length > max length");
      } else if (typeOfNumber < minTON) {
        throw new IllegalArgumentException("type of number < min");
      } else if (typeOfNumber > maxTON) {
        throw new IllegalArgumentException("type of number > max");
      } else if (text == null) {
        throw new IllegalArgumentException("text is null");
      } else if (text.length() > maxTextLength) {
        throw new IllegalArgumentException("text length > max length");
      }
    }
    setCommand("AT+CPBW=" + memoryIndex
                    + "," + number
                    + "," + typeOfNumber
                    + "," + text,
                    Command.WRITE);
  }
  
  /**
   * This will write the phonebook entry at the first free memory index.
   * If this object has been used before to run a test command to populate
   * information regarding the memory storage, then that information will be
   * used to validate the given arguments.
   * 
   * @param memoryIndex The phonebook entry to delete
   * @throws IllegalArgumentException If argument validation fails
   */
  public void prepareWrite(final String number,
                           final int typeOfNumber,
                           final String text) {
    if (informationPopulated) {
      if (number == null) {
        throw new IllegalArgumentException("number is null");
      } else if (number.length() > maxNumberLength) {
        throw new IllegalArgumentException("number length > max length");
      } else if (typeOfNumber < minTON) {
        throw new IllegalArgumentException("type of number < min");
      } else if (typeOfNumber > maxTON) {
        throw new IllegalArgumentException("type of number > max");
      } else if (text == null) {
        throw new IllegalArgumentException("text is null");
      } else if (text.length() > maxTextLength) {
        throw new IllegalArgumentException("text length > max length");
      }
    }
    setCommand("AT+CPBW="
                    + "," + number
                    + "," + typeOfNumber
                    + "," + text,
                    Command.WRITE);
  }
  
  /**
   * This will write the phonebook entry into the phonebook memory storage.
   * If the useIndex is set to true, then the index in the PhonebookEntry
   * object will be used and will overwrite any previous entry at that
   * location. If the useIndex is set to false the entry will be added at the
   * first free memory location.
   * If this object has been used before to run a test command to populate
   * information regarding the memory storage, then that information will be
   * used to validate the given arguments.
   * 
   * @param memoryIndex The phonebook entry to delete
   * @throws IllegalArgumentException If argument validation fails
   */
  public void prepareWrite(final PhonebookEntry entry,
                           final boolean useIndex) {
    final int memoryIndex = entry.getMemoryIndex();
    final int typeOfNumber = entry.getTypeOfAddress();
    final String number = entry.getNumber();
    final String text = entry.getName();
    final String index = (useIndex ? String.valueOf(memoryIndex) : "");
    
    if (informationPopulated) {
      if (number == null) {
        throw new IllegalArgumentException("number is null");
      } else if (number.length() > maxNumberLength) {
        throw new IllegalArgumentException("number length > max length");
      } else if (typeOfNumber < minTON) {
        throw new IllegalArgumentException("type of number < min");
      } else if (typeOfNumber > maxTON) {
        throw new IllegalArgumentException("type of number > max");
      } else if (text == null) {
        throw new IllegalArgumentException("text is null");
      } else if (text.length() > maxTextLength) {
        throw new IllegalArgumentException("text length > max length");
      }
    }
    setCommand("AT+CPBW=" + index
                    + "," + number
                    + "," + typeOfNumber
                    + "," + text,
                    Command.WRITE);
  }
  
  public int getFirstIndex() {
    return firstIndex;
  }
  
  public int getLastIndex() {
    return lastIndex;
  }
  
  public int getMaxNumberLength() {
    return maxNumberLength;
  }
  
  public int getMinTypeOfNumber() {
    return minTON;
  }
  
  public int getMaxTypeOfNumber() {
    return maxTON;
  }
  
  public int getMaxTextLength() {
    return maxTextLength;
  }
}
